Bytecode weaving is the process of transforming a class file conformant to the Java programming language and transforming the class file into something potentially more complicated. Typical uses of bytecode weaving include adding code to address some cross-cutting concern, for example to add method-level logging to a set of classes, or to initiate and complete global transactions around methods that write to a database. Bytecode weaving can take place at compile time, at package deployment time or at load time. (Java and all Java-based trademarks and logos are trademarks of Sun Microsystems, Inc. in the United States, other countries, or both.)
Load time bytecode weaving is generally perceived as the most flexible. It allows generic code to be created that will run on a variety of platforms. Such generic code can then be woven at the last possible moment in order to make it appropriate to, for example, a particular platform.
In order to perform bytecode weaving at class load time, it is necessary to intercept the class bytecode and modify it before it is first loaded into the runtime system. This is however not easily achievable in all environments.
The OSGi Alliance (formerly known as the Open Services Gateway Initiative) is a standards organisation which has defined a framework for remotely managing the modularity and integration of Java applications. The OSGi environment is an example of an environment in which it is not easily possible to obtain access to code before it is loaded at runtime.
The concept of an OSGi application is not standardised, but commercially available products have defined an application as a collection of OSGi bundles (code modules). The concept of a bundle is standardised in OSGi and bundles may specify dependencies on other bundles, packages or services.
Each OSGi bundle has its own class loader which is responsible for loading and defining the classes contained inside the bundle into the runtime. In order to weave a class at load time it is necessary to gain access to the class loader for the bundle that will load that class and modify its behaviour. The difficulty with the OSGi environment is that the class loader is intentionally hidden and not easily accessible.
One example of where this is particularly problematic is in relation to the Java Persistence application programming interface (API) also known as “JPA”. The JPA is an object relational mapping specification that allows client code to transparently persist Java Objects to a Relational Database and retrieve them at a later time. The JPA specifies a number of performance optimisations which are designed to reduce the amount of data that should be retrieved from the database. This is particularly noticeable when one JPA entity (the name for objects that can be persisted by JPA) references one or more other entities.
In order to support this type of optimization without requiring complex configuration or coding by clients, JPA specifies an integration point for the use of bytecode weaving. This strategy allows a JPA provider to rewrite the bytecode of an entity class so that internal state can be lazily loaded on a “just in time” basis.
In order to perform bytecode weaving, the JPA provider provides a container implementer with a ClassTransformer. This can be used by the container to transform the bytecode before it is loaded by the application's ClassLoader. In JEE this is a relatively simple task, as the JEE Application Server has complete control over the Application ClassLoader. In other environments, such as OSGi, the ClassLoader is not controlled by the container, and is not easily available to the runtime. At this point it is very difficult for the container to weave any classes at load time.
One existing solution to this problem is to use a Java Agent. These Java Agents allow container code to interpose in the class loading process, and to force class redefinition after a class has been loaded. Unfortunately, Java agents can severely impact the performance of a Java virtual machine (JVM), as they are invoked during the loading of every single class. Further to this, Java agents can expose serious security risks, as they can be used to redefine any class in the runtime, including parts of the container.
This problem is not however limited to the scope of JPA, but applies generally to the case where a container needs to apply known, or dynamically generated aspects to an application class at class load time in an OSGi framework.
One implementation of the OSGi environment, known as “Equinox” and provided by the Eclipse Foundation, has provided a workaround for the problem described above. The Equinox implementation specifies an exit point called a ClassLoadingHook which provides a mechanism to replace an original set of bytes with a new, transformed (or bytecode woven) set of bytes. This is described in Thorsten Keuler and Yury Kornev, A light-weight load-time weaving approach for OSGi, in NAOMI '08 Proceedings of the 2008 workshop on Next generation aspect oriented middleware (2008).
The solution described in the aforementioned document is however very specific to the Equinox OSGi environment, rather than being more generally applicable.